package cn.newgrand.netcall.consultant.ui;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.Timer;
import java.util.TimerTask;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.BorderFactory;
import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;

import org.jivesoftware.resource.Res;
import org.jivesoftware.resource.SparkRes;
import org.jivesoftware.smack.ConnectionListener;
import org.jivesoftware.smack.PacketListener;
//import org.jivesoftware.smack.Roster;
//import org.jivesoftware.smack.RosterEntry;
//import org.jivesoftware.smack.RosterGroup;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.filter.PacketFilter;
import org.jivesoftware.smack.filter.PacketTypeFilter;
import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.packet.Presence;
//import org.jivesoftware.smack.packet.RosterPacket;
import org.jivesoftware.smack.packet.StreamError;
import org.jivesoftware.smack.util.StringUtils;
import org.jivesoftware.smackx.LastActivityManager;
import org.jivesoftware.smackx.packet.LastActivity;
import org.jivesoftware.spark.ChatManager;
import org.jivesoftware.spark.PluginManager;
import org.jivesoftware.spark.PresenceManager;
import org.jivesoftware.spark.SparkManager;
import org.jivesoftware.spark.Workspace;
import org.jivesoftware.spark.component.VerticalFlowLayout;
import org.jivesoftware.spark.component.tabbedPane.SparkTab;
import org.jivesoftware.spark.plugin.ContextMenuListener;
import org.jivesoftware.spark.ui.ContactGroup;
import org.jivesoftware.spark.ui.ContactGroupListener;
import org.jivesoftware.spark.ui.ContactItem;
import org.jivesoftware.spark.ui.ContactList;
import org.jivesoftware.spark.ui.ContactListListener;
import cn.newgrand.netcall.consultant.ConsultantPlugin;
import cn.newgrand.netcall.consultant.SpecialistQueueManager;
import cn.newgrand.netcall.consultant.SpecialistQueueSizeManager;
import cn.newgrand.netcall.consultant.ui.RetryPanel;
import org.jivesoftware.spark.util.ModelUtil;
import org.jivesoftware.spark.util.TaskEngine;
import org.jivesoftware.spark.util.log.Log;
import org.jivesoftware.sparkimpl.profile.VCardManager;
import org.jivesoftware.sparkimpl.settings.local.LocalPreferences;
import org.jivesoftware.sparkimpl.settings.local.SettingsManager;

import cn.newgrand.netcall.base.ContactBean;
import cn.newgrand.smackx.consultant.ConsultantManager;
import cn.newgrand.netcall.consultant.SpecialistPresenceManager;
import cn.newgrand.smackx.consultant.SpecialistRoster;
import cn.newgrand.smackx.consultant.SpecialistRosterEntry;
import cn.newgrand.smackx.consultant.SpecialistRosterGroup;
import cn.newgrand.smackx.consultant.SpecialistRosterListener;
import cn.newgrand.smackx.consultant.packet.SpecialistNotifyPacket;
import cn.newgrand.smackx.consultant.packet.SpecialistPresence;
import cn.newgrand.smackx.consultant.packet.SpecialistQueueSize;

public final class SpecialistList extends JPanel implements ActionListener, SpecialistGroupListener, ConnectionListener,SpecialistRosterListener {
    private JPanel domainPanel = new JPanel();
    private JPanel productPanel = new JPanel();
    private JPanel industryPanel = new JPanel();
    private JPanel otherPanel = new JPanel();
    private JScrollPane productScrollPane;
    private JScrollPane domainScrollPane;
    private JScrollPane industryScrollPane;
    private JScrollPane otherScrollPane;
    private JScrollPane contactListScrollPane1;
    private final List<SpecialistGroup> groupList = new ArrayList<SpecialistGroup>();
    //private final RolloverButton addingGroupButton;

    private SpecialistItem activeItem;
    private SpecialistGroup activeGroup;
    private SpecialistGroup unfiledGroup;


    // Create Menus
    //private JMenuItem addContactMenu;
    //private JMenuItem addContactGroupMenu;
    //private JMenuItem removeContactFromGroupMenu;
    private JMenuItem chatMenu;
    //private JMenuItem renameMenu;

    private SpecialistGroup offlineGroup;
    //private final JCheckBoxMenuItem showHideMenu = new JCheckBoxMenuItem();
    //private final JCheckBoxMenuItem showOfflineGroupMenu = new JCheckBoxMenuItem();
    //private final JCheckBoxMenuItem showOfflineUsersMenu = new JCheckBoxMenuItem();
    
    //private List<String> sharedGroups = new ArrayList<String>();

    private final List<ContextMenuListener> contextListeners = new ArrayList<ContextMenuListener>();

    //private List<Presence> initialPresences = new ArrayList<Presence>();
    private List<SpecialistPresence> initialPresences = new ArrayList<SpecialistPresence>();
    private final Timer presenceTimer = new Timer();
    //private final List<FileDropListener> dndListeners = new ArrayList<FileDropListener>();
    private final List<SpecialistListListener> contactListListeners = new ArrayList<SpecialistListListener>();
    //private Properties props;
    //private File propertiesFile;

    private LocalPreferences localPreferences;


    public static final String RETRY_PANEL = "RETRY_PANEL";


    private RetryPanel retryPanel;

    private Workspace workspace;
    //缓存所有的联系人用于搜索等业务
    private Map<String,ContactBean> allContacts = new HashMap<String,ContactBean>();

    public static KeyEvent activeKeyEvent;
    
    private JTabbedPane specTabbedPane;
    
    private boolean isAddOther;

    /**
     * Creates a new instance of ContactList.
     */
    public SpecialistList() {
        // Load Local Preferences
        localPreferences = SettingsManager.getLocalPreferences();

        offlineGroup = new SpecialistGroup(Res.getString("group.offline"));
        //addContactMenu = new JMenuItem(Res.getString("menuitem.add.contact"), SparkRes.getImageIcon(SparkRes.USER1_ADD_16x16));
        //addContactGroupMenu = new JMenuItem(Res.getString("menuitem.add.contact.group"), SparkRes.getImageIcon(SparkRes.SMALL_ADD_IMAGE));

        //removeContactFromGroupMenu = new JMenuItem(Res.getString("menuitem.remove.from.group"), SparkRes.getImageIcon(SparkRes.SMALL_DELETE));
        chatMenu = new JMenuItem(Res.getString("menuitem.start.a.chat"), SparkRes.getImageIcon(SparkRes.SMALL_MESSAGE_IMAGE));
        //renameMenu = new JMenuItem(Res.getString("menuitem.rename"), SparkRes.getImageIcon(SparkRes.DESKTOP_IMAGE));

        //addContactMenu.addActionListener(this);
        //removeContactFromGroupMenu.addActionListener(this);
        chatMenu.addActionListener(this);
        //renameMenu.addActionListener(this);


        setLayout(new BorderLayout());
        setBackground((Color)UIManager.get("ContactList.background"));

        //addingGroupButton = new RolloverButton(SparkRes.getImageIcon(SparkRes.ADD_CONTACT_IMAGE));

        //RolloverButton groupChatButton = new RolloverButton(SparkRes.getImageIcon(SparkRes.JOIN_GROUPCHAT_IMAGE));

        //addingGroupButton.addActionListener(this);

        contactListScrollPane1 = new JScrollPane(MessageCenterPanel.getInstance());
//        contactListScrollPane1.setBorder(null);
//        contactListScrollPane1.setBackground(Color.BLACK);
//        contactListScrollPane1.setAutoscrolls(true);
//        contactListScrollPane1.setOpaque(false);
//        contactListScrollPane1.getVerticalScrollBar().setBlockIncrement(50);
//        contactListScrollPane1.getVerticalScrollBar().setUnitIncrement(20);
//        contactListScrollPane1.setSize(this.getWidth(), 0);
        add(MessageCenterPanel.getInstance(), BorderLayout.NORTH);
        
        domainPanel.setLayout(new VerticalFlowLayout(VerticalFlowLayout.TOP, 0, 0, true, false));
        domainPanel.setBackground((Color)UIManager.get("ContactItem.background"));
        domainScrollPane = new JScrollPane(domainPanel);
        domainScrollPane.setBorder(null);
        domainScrollPane.setBackground(Color.BLACK);
        domainScrollPane.setAutoscrolls(true);
        domainScrollPane.setOpaque(false);
        //TODO
//        contactListScrollPane.setBorder(BorderFactory.createEmptyBorder());
        domainScrollPane.getVerticalScrollBar().setBlockIncrement(50);
        domainScrollPane.getVerticalScrollBar().setUnitIncrement(20);
        
        productPanel.setLayout(new VerticalFlowLayout(VerticalFlowLayout.TOP, 0, 0, true, false));
        productPanel.setBackground((Color)UIManager.get("ContactItem.background"));
        productScrollPane = new JScrollPane(productPanel);
        setScrollPane(productScrollPane);
        
        industryPanel.setLayout(new VerticalFlowLayout(VerticalFlowLayout.TOP, 0, 0, true, false));
        industryPanel.setBackground((Color)UIManager.get("ContactItem.background"));
        industryScrollPane = new JScrollPane(industryPanel);
        setScrollPane(industryScrollPane);
        
        otherPanel.setLayout(new VerticalFlowLayout(VerticalFlowLayout.TOP, 0, 0, true, false));
        otherPanel.setBackground((Color)UIManager.get("ContactItem.background"));
        otherScrollPane = new JScrollPane(otherPanel);
        setScrollPane(otherScrollPane);
        
        retryPanel = new RetryPanel();

        workspace = SparkManager.getWorkspace();

        workspace.getCardPanel().add(RETRY_PANEL, retryPanel);
        
        specTabbedPane = new JTabbedPane(JTabbedPane.LEFT);
        specTabbedPane.addTab("<html>产<br>品</html>",productScrollPane);
        specTabbedPane.addTab("<html>领<br>域</html>",domainScrollPane);
        specTabbedPane.addTab("<html>行<br>业</html>",industryScrollPane);

        add(specTabbedPane, BorderLayout.CENTER);
        

        // Load Properties file
        //props = new Properties();
        // Save to properties file.
        //propertiesFile = new File(Spark.getSparkUserHome() + "/groups.properties");
       // try {
        //    props.load(new FileInputStream(propertiesFile));
       // }
       // catch (IOException e) {
            // File does not exist.
       // }

        // Add ActionListener(s) to menus
//        addContactGroup(unfiledGroup);
        //addContactGroup(offlineGroup);

        //showHideMenu.setSelected(false);

        // Add KeyMappings
//        SparkManager.getMainWindow().getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("control F"), "searchContacts");
//        SparkManager.getMainWindow().getRootPane().getActionMap().put("searchContacts", new AbstractAction("searchContacts") {
//            public void actionPerformed(ActionEvent evt) {
//                SparkManager.getUserManager().searchContacts("", SparkManager.getMainWindow());
//            }
//        });

        // Handle Command-F on Macs
//        SparkManager.getMainWindow().getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_F, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()), "appleStrokeF");
//        SparkManager.getMainWindow().getRootPane().getActionMap().put("appleStrokeF", new AbstractAction("appleStrokeF") {
//            public void actionPerformed(ActionEvent evt) {
//                SparkManager.getUserManager().searchContacts("", SparkManager.getMainWindow());
//            }
//        });

        // Save state on shutdown.
//        SparkManager.getMainWindow().addMainWindowListener(new MainWindowListener() {
//            public void shutdown() {
//                saveState();
//            }
//
//            public void mainWindowActivated() {
//
//            }
//
//            public void mainWindowDeactivated() {
//
//            }
//        });

        SparkManager.getConnection().addConnectionListener(this);

        // Get command panel and add View Online/Offline, Add Contact
//        StatusBar statusBar = SparkManager.getWorkspace().getStatusBar();
//        final JPanel commandPanel = SparkManager.getWorkspace().getCommandPanel();
//
//
//        final RolloverButton addContactButton = new RolloverButton(SparkRes.getImageIcon(SparkRes.USER1_ADD_16x16));
//        commandPanel.add(addContactButton);
//        addContactButton.setToolTipText(Res.getString("message.add.a.contact"));
//        addContactButton.addActionListener(new ActionListener() {
//            public void actionPerformed(ActionEvent e) {
//            	new UserSearchService().search(null);
//                //new RosterDialog().showRosterDialog();
//            }
//        });
    }
    
    private void setScrollPane(JScrollPane jScrollPane){
    	jScrollPane.setBorder(null);
    	jScrollPane.setBackground(Color.BLACK);
    	jScrollPane.setAutoscrolls(true);
    	jScrollPane.setOpaque(false);
    	jScrollPane.getVerticalScrollBar().setBlockIncrement(50);
    	jScrollPane.getVerticalScrollBar().setUnitIncrement(20);
    }

    /**
     * Updates the users presence.
     *
     * @param presence the user to update.
     * @throws Exception if there is a problem while updating the user's presence.
     */
    private synchronized void updateUserPresence(SpecialistPresence presence) throws Exception {
        if (presence.getError() != null) {
            // We ignore this.
            return;
        }

        final SpecialistRoster roster = ConsultantManager.getInstance(SparkManager.getConnection()).getRoster();

        final String bareJID = StringUtils.parseBareAddress(presence.getFrom());

        String spid = presence.getSpID();
        SpecialistRosterEntry entry = roster.getEntry(spid);
//        boolean isPending = entry != null && (entry.getType() == SpecialistRosterPacket.ItemType.none || entry.getType() == SpecialistRosterPacket.ItemType.from)
//            && SpecialistRosterPacket.ItemStatus.SUBSCRIPTION_PENDING == entry.getStatus();

        // If online, check to see if they are in the offline group.
        // If so, remove from offline group and add to all groups they
        // belong to.

//        if (presence.getType() == Presence.Type.available && offlineGroup.getContactItemByJID(bareJID) != null || (presence.getFrom().indexOf("workgroup.") != -1)) {
//            changeOfflineToOnline(bareJID, entry, presence);
//        }
//        else if (presence.getType() == Presence.Type.available) {
//            updateContactItemsPresence(presence, entry, bareJID);
//        }
//        else if (presence.getType() == Presence.Type.unavailable){// && !isPending) {
//            // If not available, move to offline group.
//            Presence rosterPresence = PresenceManager.getPresence(bareJID);
//            if (!rosterPresence.isAvailable()) {
//                moveToOfflineGroup(presence, bareJID);
//            }
//            else {
//                updateContactItemsPresence(rosterPresence, entry, bareJID);
//            }
//        }
        if(presence.getPresenceType().equals("online")&& offlineGroup.getContactItemBySpid(spid) != null){
        	changeOfflineToOnline(spid, entry, presence);
        }else if (presence.getPresenceType().equals("offline")) {
        	moveToOfflineGroup(presence, spid,entry);
      }
    }

    /**
     * Updates the presence of one individual based on their JID.
     *
     * @param presence the users presence.
     * @param entry    the roster entry being updated.
     * @param bareJID  the bare jid of the user.
     */
    private void updateContactItemsPresence(SpecialistPresence presence, SpecialistRosterEntry entry, String spid) {
        for (SpecialistGroup group : groupList) {
        	SpecialistItem item = group.getContactItemBySpid(spid);
            if (item != null) {
                if (group == offlineGroup) {
                    changeOfflineToOnline(spid, entry, presence);
                    continue;
                }
                item.setPresence(presence);
                group.fireContactGroupUpdated();
            }
        }
    }

    /**
     * Moves every <code>SpecialistItem</code> associated with the given bareJID to offline.
     *
     * @param presence the users presence.
     * @param bareJID  the bareJID of the user.
     */
    private void moveToOfflineGroup(final SpecialistPresence presence, final String spid,SpecialistRosterEntry entry) {
//        for (SpecialistGroup grpItem : new ArrayList<SpecialistGroup>(groupList)) {
//            final SpecialistGroup group = grpItem;
//            final SpecialistItem item = group.getContactItemByJID(bareJID);
//            if (item != null) {
//                int numberOfMillisecondsInTheFuture = 3000;
//                Date timeToRun = new Date(System.currentTimeMillis() + numberOfMillisecondsInTheFuture);
//
//                // Only run through if the users presence was online before.
//                if (item.getPresence().isAvailable()) {
//                    item.showUserGoingOfflineOnline();
//                    item.setIcon(SparkRes.getImageIcon(SparkRes.CLEAR_BALL_ICON));
//                    group.fireContactGroupUpdated();
//
//                    final Timer offlineTimer = new Timer();
//                    offlineTimer.schedule(new TimerTask() {
//                        public void run() {
//                            // Check to see if the user is offline, if so, move them to the offline group.
//                            Presence userPresence = PresenceManager.getPresence(bareJID);
//                            if (userPresence.isAvailable()) {
//                                return;
//                            }
//
//                            item.setPresence(presence);
//
//                            // Check for ContactItemHandler.
//                            group.removeContactItem(item);
//                            checkGroup(group);
//
//                            if (offlineGroup.getContactItemByJID(item.getJID()) == null) {
//                                moveToOffline(item);
//                                offlineGroup.fireContactGroupUpdated();
//                            }
//                        }
//                    }, timeToRun);
//                }
//            } else {
//                final SpecialistItem offlineItem = offlineGroup.getContactItemByJID(bareJID);
//                if (offlineItem != null) {
//                    offlineItem.setPresence(presence);
//                }
//            }
//        }
    	if(entry.getGroups().iterator().hasNext()){
            final SpecialistGroup group = getContactGroup(entry.getGroups().iterator().next().getName());

            final SpecialistItem item = group.getContactItemBySpid(spid);
            if (item != null) {
                int numberOfMillisecondsInTheFuture = 3000;
                Date timeToRun = new Date(System.currentTimeMillis() + numberOfMillisecondsInTheFuture);

                // Only run through if the users presence was online before.
                if (item.getPresence().isAvailable()) {
                    item.showUserGoingOfflineOnline();
                    item.setIcon(SparkRes.getImageIcon(SparkRes.CLEAR_BALL_ICON));
                    group.fireContactGroupUpdated();

                    final Timer offlineTimer = new Timer();
                    offlineTimer.schedule(new TimerTask() {
                        public void run() {
                            // Check to see if the user is offline, if so, move them to the offline group.
                        	SpecialistPresence userPresence = ConsultantManager.getInstance(SparkManager.getConnection()).getRoster().getPresence(presence.getSpID());
                            if (userPresence.isAvailable()) {
                                return;
                            }

                            item.setPresence(presence);

                            // Check for ContactItemHandler.
                            group.removeContactItem(item);
                            //checkGroup(group);

                            if (offlineGroup.getContactItemBySpid(item.getAlias()) == null) {
                                moveToOffline(item);
                                offlineGroup.fireContactGroupUpdated();
                            }
                        }
                    }, timeToRun);
                }
            } else {
                final SpecialistItem offlineItem = offlineGroup.getContactItemBySpid(spid);
                if (offlineItem != null) {
                    offlineItem.setPresence(presence);
                }
            }
    	}
    }

    /**
     * Moves a user to each group they belong to.
     *
     * @param bareJID  the bareJID of the user to show as online.
     * @param entry    the <code>RosterEntry</code> of the user.
     * @param presence the users presence.
     */
    private void changeOfflineToOnline(String spid, final SpecialistRosterEntry entry, SpecialistPresence presence) {
        // Move out of offline group. Add to all groups.
        SpecialistItem offlineItem = offlineGroup.getContactItemBySpid(spid);
        if (offlineItem == null) {
            return;
        }

        offlineGroup.removeContactItem(offlineItem);

        // Add To all groups it belongs to.
//        boolean isFiled = false;
        for (SpecialistRosterGroup rosterGroup : entry.getGroups()) {
//            isFiled = true;
            SpecialistGroup contactGroup = getContactGroup(rosterGroup.getName());
            if (contactGroup == null) {
                // Create Contact Group
                contactGroup = addContactGroup(rosterGroup.getName());
            }

            if (contactGroup != null) {
                 SpecialistItem contactItem = null;
                if (contactGroup.getContactItemBySpid(entry.getName()) == null) {
                    contactItem = new SpecialistItem(entry.getName(), entry.getTruename(), entry.getUser());
                    contactGroup.addContactItem(contactItem);
                }
                else if (contactGroup.getContactItemBySpid(entry.getName()) != null) {
                    // If the user is in their, but without a nice presence.
                    contactItem = contactGroup.getContactItemBySpid(entry.getName());
                }

                try {
                    contactItem.setPresence(presence);
                }
                catch (NullPointerException e) {
                    // TODO: Hrm, what should we do in this scenario?
                }
                contactItem.setAvailable(true);
                toggleGroupVisibility(contactGroup.getGroupName(), true);

                contactItem.updateAvatarInSideIcon();
                contactItem.showUserComingOnline();
                contactGroup.fireContactGroupUpdated();


                int numberOfMillisecondsInTheFuture = 5000;
                Date timeToRun = new Date(System.currentTimeMillis() + numberOfMillisecondsInTheFuture);
                Timer timer = new Timer();

                final SpecialistItem staticItem = contactItem;
                final SpecialistGroup staticGroup = contactGroup;
                timer.schedule(new TimerTask() {
                    public void run() {
                        staticItem.updatePresenceIcon(staticItem.getPresence());
                        staticGroup.fireContactGroupUpdated();
                    }
                }, timeToRun);
            }
        }

//        if (!isFiled) {
//            SpecialistItem contactItem = new SpecialistItem(entry.getName(), null, entry.getUser());
//            if (unfiledGroup == null) {
//                unfiledGroup = new SpecialistGroup(Res.getString("unfiled"));
//                addContactGroup(unfiledGroup);
//            }
//            unfiledGroup.addContactItem(contactItem);
//            contactItem.setPresence(presence);
//            contactItem.setAvailable(true);
//
//            unfiledGroup.setVisible(true);
//            unfiledGroup.fireContactGroupUpdated();
//        }
    }


    /**
     * Called to build the initial ContactList.
     */
    private void buildContactList() {	
        XMPPConnection con = SparkManager.getConnection();
        final SpecialistRoster roster =  ConsultantManager.getInstance(con).getRoster();
        
        SpecialistQueueSizeManager.getInstance().sendQueueSizePacket();
        
        TaskEngine.getInstance().schedule(new TimerTask() {
			@Override
			public void run() {
				roster.addRosterListener(SpecialistList.this);
			}
		}, 2000);

        //清除搜索联系人
        allContacts.clear();
        // Add All Groups to List
        for (SpecialistRosterGroup group : roster.getGroups()) {
            addContactGroup(group.getName());
        }

        for (SpecialistRosterGroup group : roster.getGroups()) {
            SpecialistGroup contactGroup = getContactGroup(group.getName());
            
            for (SpecialistRosterEntry entry : group.getEntries()) {
                SpecialistItem contactItem = new SpecialistItem(entry.getName(), entry.getTruename(), entry.getUser());
                contactItem.setPresence(new SpecialistPresence("offline"));
//                if ((entry.getType() == SpecialistRosterPacket.ItemType.none || entry.getType() == SpecialistRosterPacket.ItemType.from)
//                    && SpecialistRosterPacket.ItemStatus.SUBSCRIPTION_PENDING == entry.getStatus()) {
//                    // Add to contact group.
//                    contactGroup.addContactItem(contactItem);
//                    contactGroup.setVisible(true);
//                }
//                else {
                    if (offlineGroup.getContactItemBySpid(entry.getName()) == null) {
                        moveToOffline(contactItem);
                    }
//                }
                //将联系人添加到搜索联系人中
               ContactBean bean = new  ContactBean(entry.getUser(),entry.getUser().split("@")[0],entry.getName(),entry.getTruename());
               bean.setGroupName(group.getName());
               // allContacts.put(entry.getUser(),bean);
               allContacts.put(entry.getName(),bean);
            }
        }

//        // Add Unfiled Group
//        for (SpecialistRosterEntry entry : roster.getUnfiledEntries()) {
//            if (unfiledGroup == null) {
//                unfiledGroup = addContactGroup(Res.getString("unfiled"));
//                
//            }
//            //修改"我的联系人"组中联系人(离线状态)，如果在共享组中的话，会不显示
//            //modified by sidney
//            SpecialistItem contactItem = new SpecialistItem(entry.getName(), null, entry.getUser());
//            moveUnfiledToOffline(contactItem);
//
//            //将联系人添加到搜索联系人中,供搜索用
//            if(null==allContacts.get(entry.getUser())){
//            	ContactBean bean = new ContactBean(entry.getUser(),entry.getUser().split("@")[0],entry.getName(),null);
//            	bean.setGroupName("");
//            	allContacts.put(entry.getUser(),bean);
//            }
//        }
    }

    /**
     * Called when NEW entries are added.
     *
     * @param addresses the address added.
     */
    public void entriesAdded(final Collection addresses) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
            	SpecialistRoster roster =  ((ConsultantPlugin)PluginManager.getInstance().getPlugin(ConsultantPlugin.class)).getConsultantManager().getRoster();;

                for (Object address : addresses) {
                    String jid = (String) address;
                    SpecialistRosterEntry entry = roster.getEntry(jid);
                    addUser(entry);
                }
            }
        });
    }

    /**
     * Adds a single user to the ContactList.
     *
     * @param entry the <code>RosterEntry</code> of the the user.
     */
    private void addUser(SpecialistRosterEntry entry) {
        SpecialistItem newContactItem = new SpecialistItem(entry.getName(), entry.getTruename(), entry.getUser());
        //添加到所有联系人列表中
        ContactBean bean = new ContactBean(entry.getUser(),entry.getUser().split("@")[0],entry.getName(),null);
        bean.setGroupName("");
        allContacts.put(entry.getUser(),bean);
//fangt SpecialistRosterPacket.ItemStatus.SUBSCRIPTION_PENDING表示已发出订阅请求，还未得到回应,这里不需要
        //fangt 这里可以看出对于已发出订阅请求还未得到回应的，我们也将其加入联系人列表，并可见。但那些在名册有，但又不是正在请求订阅的就设为不可见
//        if (entry.getType() == SpecialistRosterPacket.ItemType.none || entry.getType() == SpecialistRosterPacket.ItemType.from) {
//            // Ignore, since the new user is pending to be added.
//            for (SpecialistRosterGroup group : entry.getGroups()) {
//                SpecialistGroup contactGroup = getContactGroup(group.getName());
//                if (contactGroup == null) {
//                    contactGroup = addContactGroup(group.getName());
//                }
//
//                boolean isPending = entry.getType() == SpecialistRosterPacket.ItemType.none || entry.getType() == SpecialistRosterPacket.ItemType.from
//                    && SpecialistRosterPacket.ItemStatus.SUBSCRIPTION_PENDING == entry.getStatus();
//                if (isPending) {
//                    contactGroup.setVisible(true);
//                }
//                contactGroup.addContactItem(newContactItem);
//
//            }
//            return;
//        }
//        else {
            moveToOffline(newContactItem);
//        }

        // Update users icon
        //Presence presence = SparkManager.getConnection().getRoster().getPresence(entry.getUser());
       SpecialistPresence presence =  ConsultantManager.getInstance(SparkManager.getConnection()).getRoster().getPresence(entry.getName());
        try {
            updateUserPresence(presence);
        }
        catch (Exception e) {
            Log.error(e);
        }
    }

    /**
     * Handle when the Roster changes based on subscription notices.
     *
     * @param addresses List of entries that were updated.
     */
    public void entriesUpdated(final Collection addresses) {
        handleEntriesUpdated(addresses);
    }

    /**
     * Called when users are removed from the roster.
     *
     * @param addresses the addresses removed from the roster.
     */
    public void entriesDeleted(final Collection addresses) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                for (Object address : addresses) {
                    String jid = (String) address;
	                    removeContactItem(jid);
                }
            }
        });

    }

    /**
     * Handles any presence modifications of a user(s).
     *
     * @param addresses the Collection of addresses that have been modified within the Roster.
     */
    private synchronized void handleEntriesUpdated(final Collection addresses) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
            	SpecialistRoster roster =  ((ConsultantPlugin)PluginManager.getInstance().getPlugin(ConsultantPlugin.class)).getConsultantManager().getRoster();;

                Iterator jids = addresses.iterator();
                while (jids.hasNext()) {
                    String jid = (String)jids.next();//此处jid直接换成spid其他不变
                    SpecialistRosterEntry rosterEntry = roster.getEntry(jid);
                    if (rosterEntry != null) {
                        // Check for new Roster Groups and add them if they do not exist.
//                        boolean isUnfiled = true;
                        for (SpecialistRosterGroup group : rosterEntry.getGroups()) {
//                            isUnfiled = false;

                            // Handle if this is a new Entry in a new Group.
                            // 处理在新组中加入该联系人。即先创建组，然后在加人
                            if (getContactGroup(group.getName()) == null) {
                                // Create group.
                                SpecialistGroup contactGroup = addContactGroup(group.getName());
                                contactGroup.setVisible(false);
                                contactGroup = getContactGroup(group.getName());
                                SpecialistItem contactItem = new SpecialistItem(rosterEntry.getName(), rosterEntry.getTruename(), rosterEntry.getUser());
                                contactGroup.addContactItem(contactItem);
                                //Presence presence = PresenceManager.getPresence(jid);
                                SpecialistPresence presence = SpecialistPresenceManager.getSpecialistPresence(rosterEntry.getName());
                                contactItem.setPresence(presence);
                                if (presence.isAvailable()) {
                                    contactGroup.setVisible(true);
                                }
                            }
                            else {
                                SpecialistGroup contactGroup = getContactGroup(group.getName());
                                SpecialistItem item = offlineGroup.getContactItemBySpid(jid);
                                
                                //增加、删除、组中在线、不在线的联系人
                                //检查过程：检查offlineGroup，没有，则检查组(包括在线的和不在线的两部分)
                                //如果不存在则创建，并加到该组中，如果存在于则只做更新(在线状态操作)
                                //modified by sidney
                                SpecialistItem temp = contactGroup.getContactItemBySpid(jid);
                            	temp = null==temp?contactGroup.getOfflineContactItemBySpid(jid):temp;
                            	
                                if (item == null) {
                                	item = temp;
                                }
                                
                                //判断组中是否已经有该联系人，如果没有则要添加到组中的离线联系人列表
                            	if(null==temp){
	                            	contactGroup.addOfflineContactItem(rosterEntry.getName(), null, rosterEntry.getUser(),null);
                            	}
                                
                                // Check to see if this entry is new to a pre-existing group.
                                // 检查该联系人在原来组中是否存在，如果存在则只做更新presence(在线状态)的动作
                                if (item == null) {
                                    item = new SpecialistItem(rosterEntry.getName(), rosterEntry.getTruename(), rosterEntry.getUser());
                                    //Presence presence = PresenceManager.getPresence(jid);
                                    SpecialistPresence presence = SpecialistPresenceManager.getSpecialistPresence(rosterEntry.getName());
                                    item.setPresence(presence);
                                    if (presence.isAvailable()) {
                                        contactGroup.addContactItem(item);
                                        contactGroup.fireContactGroupUpdated();
                                    }
                                    else {
                                    	//面板的离线联系人中去
                                        moveToOffline(item);
                                        offlineGroup.fireContactGroupUpdated();
                                    }
                                	
                                }
                                // If not, just update their presence.
                                else {
                                	SpecialistRosterEntry entry = roster.getEntry(jid);
                                    //Presence presence = PresenceManager.getPresence(jid);
                                	SpecialistPresence presence = SpecialistPresenceManager.getSpecialistPresence(rosterEntry.getName());
                                    item.setPresence(presence);
                                    try {
                                        updateUserPresence(presence);
                                    }
                                    catch (Exception e) {
                                        Log.error(e);
                                    }

//                                    if (entry != null && (entry.getType() == SpecialistRosterPacket.ItemType.none || entry.getType() == SpecialistRosterPacket.ItemType.from)
//                                        && SpecialistRosterPacket.ItemStatus.SUBSCRIPTION_PENDING == entry.getStatus()) {
//                                        contactGroup.setVisible(true);
//
//                                    }
                                    contactGroup.fireContactGroupUpdated();
                                }
                            }
                        }

                        // Now check to see if groups have been modified or removed. This is used
                        // to check if Contact Groups have been renamed or removed.
                        //上面为原来的注释，
                        //在 原面板中更新/删除联系人
                        final Set<String> userGroupSet = new HashSet<String>();
                        jids = addresses.iterator();
                        while (jids.hasNext()) {
                            jid = (String)jids.next();
                            rosterEntry = roster.getEntry(jid);

                            boolean unfiled = true;
                            for (SpecialistRosterGroup g : rosterEntry.getGroups()) {
                                userGroupSet.add(g.getName());
                                unfiled = false;
                            }

                            for (SpecialistGroup group : new ArrayList<SpecialistGroup>(getContactGroups())) {
                                SpecialistItem itemFound = group.getContactItemBySpid(jid);
                                if(null==itemFound){
                                	itemFound = group.getOfflineContactItemBySpid(jid);
                                }
                                if (itemFound != null && !unfiled && group != unfiledGroup && group != offlineGroup) {
                                    if (!userGroupSet.contains(group.getGroupName())) {
                                    	//modified by sidney
                                    	//删除组中不在线的联系人
//                                        group.removeContactItem(itemFound);
                                        group.removeOfflineContactItem(itemFound);
//                                    	removeContactGroup(group);
                                    }
                                }

                            }
                        }


//                        if (!isUnfiled) {
//                            return;
//                        }

//                        SpecialistItem unfiledItem = unfiledGroup.getContactItemByJID(jid);
//                        if (unfiledItem != null) {
//
//                        }
//                        else {
//                            SpecialistItem offlineItem = offlineGroup.getContactItemByJID(jid);
//                            if (offlineItem != null) {
//                                if ((rosterEntry.getType() == SpecialistRosterPacket.ItemType.none || rosterEntry.getType() == SpecialistRosterPacket.ItemType.from)
//                                    && SpecialistRosterPacket.ItemStatus.SUBSCRIPTION_PENDING == rosterEntry.getStatus()) {
//                                    // Remove from offlineItem and add to unfiledItem.
//                                    offlineGroup.removeContactItem(offlineItem);
//                                    unfiledGroup.addContactItem(offlineItem);
//                                    unfiledGroup.fireContactGroupUpdated();
//                                    unfiledGroup.setVisible(true);
//                                }
//                            }
//                        }
                    }
                }
            }
        });
    }

    public void presenceChanged(SpecialistPresence presence) {

    }

    /**
     * Retrieve the SpecialistItem by it's jid.
     *
     * @param jid the JID of the user.
     * @return the "first" contact item found.
     */
    public SpecialistItem getContactItemBySpid(String spid) {
        for (SpecialistGroup group : getContactGroups()) {
            SpecialistItem item = group.getContactItemBySpid(spid);
            if (item != null) {
                return item;
            }
        }
        return null;
    }
    
    public SpecialistItem getContactItemBySpid(String spid,boolean includeOffline) {
        for (SpecialistGroup group : getContactGroups()) {
            SpecialistItem item = group.getContactItemBySpid(spid,true);
            if (item != null) {
                return item;
            }
        }
        return null;
    }
    /**
     * Returns a Collection of ContactItems in a ContactList.
     *
     * @param jid the users JID.
     * @return a Collection of <code>SpecialistItem</code> items.
     */
    public Collection<SpecialistItem> getContactItemsBySpid(String spid) {
        final List<SpecialistItem> list = new ArrayList<SpecialistItem>();
        for (SpecialistGroup group : getContactGroups()) {
            SpecialistItem item = group.getContactItemBySpid(spid);
            if (item != null) {
                list.add(item);
            }
        }

        return list;
    }

    /**
     * Set an Icon for all ContactItems that match the given jid.
     *
     * @param jid  the users jid.
     * @param icon the icon to use.
     */
    public void setIconFor(String spid, Icon icon) {
        for (SpecialistGroup group : getContactGroups()) {
            SpecialistItem item = group.getContactItemBySpid(spid);
            if (item != null) {
                item.setIcon(icon);
                group.fireContactGroupUpdated();
            }
        }
    }

    /**
     * Sets the default settings for a SpecialistItem.
     *
     * @param jid the users jid.
     */
    public void useDefaults(String spid) {
        for (SpecialistGroup group : getContactGroups()) {
            SpecialistItem item = group.getContactItemBySpid(spid);
            if (item != null) {
                item.updatePresenceIcon(item.getPresence());
                group.fireContactGroupUpdated();
            }
        }
    }


    /**
     * Retrieve the SpecialistItem by their displayed name (either alias, nickname or username).
     *
     * @param displayName the users nickname in the contact list.
     * @return the "first" contact item found.
     */
    public SpecialistItem getContactItemByDisplayName(String displayName) {
        for (SpecialistGroup contactGroup : getContactGroups()) {
            SpecialistItem item = contactGroup.getContactItemByDisplayName(displayName);
            if (item != null) {
                return item;
            }
        }
        return null;
    }

    /**
     * Adds a new SpecialistGroup to the ContactList.
     *
     * @param group the group to add.
     */
    private void addContactGroup(SpecialistGroup group) {
        groupList.add(group);

        Collections.sort(groupList, GROUP_COMPARATOR);

        try {
        	domainPanel.add(group, groupList.indexOf(group));
        }
        catch (Exception e) {
            Log.error(e);
        }

        group.addContactGroupListener(this);

//        fireContactGroupAdded(group);

        // Check state
//        String prop = props.getProperty(group.getGroupName());
//        if (prop != null) {
//            boolean isCollapsed = Boolean.valueOf(prop);
//            group.setCollapsed(isCollapsed);
//        }
    }


    /**
     * Creates and adds a new SpecialistGroup to the ContactList.
     *
     * @param groupName the name of the SpecialistGroup to add.
     * @return the newly created SpecialistGroup.
     */
    private SpecialistGroup addContactGroup(String groupName) {
        StringTokenizer tkn = new StringTokenizer(groupName, "::");

        SpecialistGroup rootGroup = null;
        SpecialistGroup lastGroup = null;
        StringBuffer buf = new StringBuffer();

        boolean groupAdded = false;
        while (tkn.hasMoreTokens()) {
            String group = tkn.nextToken();
            buf.append(group);
            if (tkn.hasMoreTokens()) {
                buf.append("::");
            }

            String name = buf.toString();
            if (name.endsWith("::")) {
                name = name.substring(0, name.length() - 2);
            }

            SpecialistGroup newContactGroup = getContactGroup(name);


            if (newContactGroup == null) {
                newContactGroup = new SpecialistGroup(group);

                String realGroupName = buf.toString();
                if (realGroupName.endsWith("::")) {
                    realGroupName = realGroupName.substring(0, realGroupName.length() - 2);
                }

                newContactGroup.setGroupName(realGroupName);
            }
            else {
                if (newContactGroup != offlineGroup && newContactGroup != unfiledGroup) {
                    rootGroup = newContactGroup;//这里的子组也当成根节点了
                    continue;
                }
            }


            if (lastGroup != null) {
                lastGroup.addContactGroup(newContactGroup);
                groupList.add(newContactGroup);
            }
            else if (rootGroup != null) {
                rootGroup.addContactGroup(newContactGroup);
                groupList.add(newContactGroup);
            }
            else {
                rootGroup = newContactGroup;
            }

            lastGroup = newContactGroup;


            newContactGroup.addContactGroupListener(this);

//            if (sharedGroups != null) {
//                boolean isSharedGroup = sharedGroups.contains(newContactGroup.getGroupName());
//                newContactGroup.setSharedGroup(isSharedGroup);
//            }

//            fireContactGroupAdded(newContactGroup);

            // Check state

//            String prop = props.getProperty(newContactGroup.getGroupName());
//            if (prop != null) {
//                boolean isCollapsed = Boolean.valueOf(prop);
//                newContactGroup.setCollapsed(isCollapsed);
//            }


            groupAdded = true;
        }

        if (!groupAdded) {
            return getContactGroup(groupName);
        }
        
        //判断rootGroup的领域产品 增加到相应的面板


//        final List<SpecialistGroup> tempList = new ArrayList<SpecialistGroup>();
//        final Component[] comps = mainPanel.getComponents();
//        for (Component c : comps) {
//            if (c instanceof SpecialistGroup && c != offlineGroup) {
//                tempList.add((SpecialistGroup)c);
//            }
//        }
//        if(!tempList.contains(rootGroup)){
//        	tempList.add(rootGroup);
//        }
//
        if(!groupList.contains(rootGroup)){
        	groupList.add(rootGroup);
        }
//
//        Collections.sort(tempList, GROUP_COMPARATOR);
//
//        int loc = tempList.indexOf(rootGroup);
//
//
//        try {
//        	if(!rootGroup.getGroupName().contains("::"))
//        		mainPanel.add(rootGroup, loc);
//        }
//        catch (Exception e) {
//            Log.error(e);
//        }
      try {
	    	if(!rootGroup.getGroupName().contains("::") && rootGroup.getGroupName().equals("产品")){
	    		for (SpecialistGroup group : rootGroup.getContactGroups()) {
	    			group.setSubPane(false);
	    			productPanel.add(group);
				}
	    		//productPanel.add(rootGroup);
	    	}else if(!rootGroup.getGroupName().contains("::") && rootGroup.getGroupName().equals("领域")){
	    		for (SpecialistGroup group : rootGroup.getContactGroups()) {
	    			group.setSubPane(false);
	    			domainPanel.add(group);
				}
	    		//domainPanel.add(rootGroup);
	    	}else if(!rootGroup.getGroupName().contains("::") && rootGroup.getGroupName().equals("行业")){
	    		for (SpecialistGroup group : rootGroup.getContactGroups()) {
	    			group.setSubPane(false);
	    			industryPanel.add(group);
				}
	    		//industryPanel.add(rootGroup);
	    	}else if(!rootGroup.getGroupName().contains("::")){
	    		if(!isAddOther){
	    			addOtherScrollPanel();
	    		}
	    		otherPanel.add(rootGroup);
	    	}
	    }
	    catch (Exception e) {
	        Log.error(e);
	    }

        return getContactGroup(groupName);

    }
    
    private void addOtherScrollPanel(){
    	specTabbedPane.addTab("<html>其<br>它</html>",otherScrollPane);
    	isAddOther = true;
    }

    public JTabbedPane getTabbedPane(){
    	return specTabbedPane;
    }
//    /**
//     * Removes a SpecialistGroup from the group model and ContactList.
//     *
//     * @param contactGroup the SpecialistGroup to remove.
//     */
//    private void removeContactGroup(SpecialistGroup contactGroup) {
//        contactGroup.removeContactGroupListener(this);
//        groupList.remove(contactGroup);
//        mainPanel.remove(contactGroup);
//
//        SpecialistGroup parent = getParentGroup(contactGroup.getGroupName());
//        if (parent != null) {
//            parent.removeContactGroup(contactGroup);
//        }
//
//        contactListScrollPane.validate();
//        mainPanel.invalidate();
//        mainPanel.repaint();
//
//        fireContactGroupRemoved(contactGroup);
//    }


    /**
     * Returns a SpecialistGroup based on its name.
     *
     * @param groupName the name of the SpecialistGroup.
     * @return the SpecialistGroup. If no SpecialistGroup is found, null is returned.
     */
    public SpecialistGroup getContactGroup(String groupName) {
        SpecialistGroup cGroup = null;

        for (SpecialistGroup contactGroup : groupList) {
            if (contactGroup.getGroupName().equals(groupName)) {
                cGroup = contactGroup;
                break;
            }
            else {
                cGroup = getSubContactGroup(contactGroup, groupName);
                if (cGroup != null) {
                    break;
                }
            }
        }

        return cGroup;
    }

    /**
     * For traversing of a nested group. Allows users to find the owning parent of a given contact group.
     *
     * @param groupName the name of the nested contact group.
     * @return the parent SpecialistGroup. If no parent, null will be returned.
     */
    public SpecialistGroup getParentGroup(String groupName) {
        // Check if there is even a parent group
        if (!groupName.contains("::")) {
            return null;
        }

        final SpecialistGroup group = getContactGroup(groupName);
        if (group == null) {
            return null;
        }

        // Otherwise, find parent
        int index = groupName.lastIndexOf("::");
        String parentGroupName = groupName.substring(0, index);
        return getContactGroup(parentGroupName);
    }

    /**
     * Returns the nested SpecialistGroup of a given SpecialistGroup with associated name.
     *
     * @param group     the parent SpecialistGroup.
     * @param groupName the name of the nested group.
     * @return the nested SpecialistGroup. If not found, null will be returned.
     */
    private SpecialistGroup getSubContactGroup(SpecialistGroup group, String groupName) {
        final Iterator contactGroups = group.getContactGroups().iterator();
        SpecialistGroup grp = null;

        while (contactGroups.hasNext()) {
            SpecialistGroup contactGroup = (SpecialistGroup)contactGroups.next();
            if (contactGroup.getGroupName().equals(groupName)) {
                grp = contactGroup;
                break;
            }
            else if (contactGroup.getContactGroups().size() > 0) {
                grp = getSubContactGroup(contactGroup, groupName);
                if (grp != null) {
                    break;
                }
            }

        }
        return grp;
    }

    /**
     * Toggles the visiblity of a SpecialistGroup.
     *
     * @param groupName the name of the SpecialistGroup.
     * @param visible   true to show, otherwise false.
     */
    public void toggleGroupVisibility(String groupName, boolean visible) {
        StringTokenizer tkn = new StringTokenizer(groupName, "::");
        while (tkn.hasMoreTokens()) {
            String group = tkn.nextToken();
            SpecialistGroup contactGroup = getContactGroup(group);
            if (contactGroup != null) {
                contactGroup.setVisible(visible);
            }
        }

        SpecialistGroup group = getContactGroup(groupName);
        if (group != null) {
            group.setVisible(true);
        }
    }
	//右键菜单执行
    public void actionPerformed(ActionEvent e) {
//        if (e.getSource() == addingGroupButton) {
//            new RosterDialog().showRosterDialog();
//        }else
    	if (e.getSource() == chatMenu) {
            if (activeItem != null) {
                SparkManager.getChatManager().activateChat(activeItem.getJID(), activeItem.getDisplayName());
            }
        }
//        else if (e.getSource() == addContactMenu) {
//        	new UserSearchService().search(null);
//
////            RosterDialog rosterDialog = new RosterDialog();
////            if (activeGroup != null) {
////                rosterDialog.setDefaultGroup(activeGroup);
////            }
////            rosterDialog.showRosterDialog();
//        }
//        else if (e.getSource() == removeContactFromGroupMenu) {
//            if (activeItem != null) {
//                removeContactFromGroup(activeItem);
//            }
//        }
//        else if (e.getSource() == renameMenu) {
//            if (activeItem == null) {
//                return;
//            }
//
//            String oldAlias = activeItem.getAlias();
//            String newAlias = JOptionPane.showInputDialog(this, Res.getString("label.rename.to") + ":", oldAlias);
//            
//            // if user pressed 'cancel', output will be null.
//        	// if user removed alias, output will be an empty String.
//            if (newAlias != null) {
//	            if (!ModelUtil.hasLength(newAlias)) {
//	            	newAlias = null; // allows you to remove an alias.
//	            }
//	            
//	            String address = activeItem.getJID();
//	            SpecialistGroup contactGroup = getContactGroup(activeItem.getGroupName());
//	            SpecialistItem contactItem = contactGroup.getContactItemByDisplayName(activeItem.getDisplayName());
//	            contactItem.setAlias(newAlias);
//	
//	            final Roster roster = SparkManager.getConnection().getRoster();
//	            RosterEntry entry = roster.getEntry(address);
//	            entry.setName(newAlias);
//	
//	
//	            final Iterator contactGroups = groupList.iterator();
//	            String user = StringUtils.parseBareAddress(address);
//	            while (contactGroups.hasNext()) {
//	                SpecialistGroup cg = (SpecialistGroup)contactGroups.next();
//	                SpecialistItem ci = cg.getContactItemByJID(user);
//	                if (ci != null) {
//	                    ci.setAlias(newAlias);
//	                }
//	            }
//            }
//        }
    }


//    /**
//     * Removes a contact item from the group.
//     *
//     * @param item the SpecialistItem to remove.
//     */
//    private void removeContactFromGroup(SpecialistItem item) {
//        String groupName = item.getGroupName();
//        SpecialistGroup contactGroup = getContactGroup(groupName);
//        Roster roster = SparkManager.getConnection().getRoster();
//        RosterEntry entry = roster.getEntry(item.getJID());
//        if (entry != null && contactGroup != offlineGroup) {
//            try {
//                RosterGroup rosterGroup = roster.getGroup(groupName);
//                if (rosterGroup != null) {
//                    RosterEntry rosterEntry = rosterGroup.getEntry(entry.getUser());
//                    if (rosterEntry != null) {
//                        rosterGroup.removeEntry(rosterEntry);
//                    }
//                }
////                contactGroup.removeContactItem(contactGroup.getContactItemByJID(item.getJID()));
//                //修改原先代码，可同时删除组中在线/离线的联系人
//                contactGroup.removeOfflineContactItem(contactGroup.getContactItemByJID(item.getJID()));
//                checkGroup(contactGroup);
//            }
//            catch (Exception e) {
//                Log.error("Error removing user from contact list.", e);
//            }
//        }
//    }

//    private void removeContactFromRoster(SpecialistItem item) {
//        Roster roster = SparkManager.getConnection().getRoster();
//        RosterEntry entry = roster.getEntry(item.getJID());
//        if (entry != null) {
//            try {
//                roster.removeEntry(entry);
//                //同时在所有联系人中删除
//                allContacts.remove(item.getJID());
//            }
//            catch (XMPPException e) {
//                Log.warning("Unable to remove roster entry.", e);
//            }
//        }
//    }

    private void removeContactItem(String spid) {
        for (SpecialistGroup group : new ArrayList<SpecialistGroup>(getContactGroups())) {
            SpecialistItem item = group.getContactItemBySpid(spid);
            group.removeOfflineContactItem(spid);
            if (item != null) {
                group.removeContactItem(item);
                checkGroup(group);
            }
        }
    }

    public void contactItemClicked(SpecialistItem item) {
        activeItem = item;

        if (activeKeyEvent == null || ((activeKeyEvent.getModifiers() & KeyEvent.CTRL_MASK) == 0)) {
            clearSelectionList(item);
        }


        fireContactItemClicked(item);
        activeKeyEvent = null;
    }

    public void contactItemDoubleClicked(SpecialistItem item) {
        activeItem = item;

        
        //双击事件的发生
//        ChatManager chatManager = SparkManager.getChatManager();
//        boolean handled = chatManager.fireContactItemDoubleClicked(item);
//
//        if (!handled) {
//            chatManager.activateChat(item.getJID(), item.getDisplayName());
//        }
        String spid = activeItem.getAlias();
        String user = activeItem.getJID();
        String trueName = activeItem.getNickname();
        final SpecialistPresence specialistPresence = SpecialistPresenceManager.getSpecialistPresence(spid);
        if(specialistPresence.isAvailable()){
        	joinSpecialQueue(spid);
        }else{
        	//JOptionPane.showMessageDialog(SparkManager.getMainWindow(), "专家不在线,无法加入队列");
        	if(!user.equals(SparkManager.getConnection().getUser())){
        		new LeaveWordSendPanel(spid,user,trueName);
        	}else{
        		JOptionPane.showMessageDialog(SparkManager.getMainWindow(), "无法加入自己的队列");
        	}
        }

        clearSelectionList(item);

        fireContactItemDoubleClicked(item);
    }

    public void contactGroupPopup(MouseEvent e, final SpecialistGroup group) {
   	  // Do nothing with offline group
        if (group == offlineGroup || group == unfiledGroup) {
            return;
        }


        final JPopupMenu popup = new JPopupMenu();
//        popup.add(addContactMenu);
//        popup.add(addContactGroupMenu);
//        popup.addSeparator();

        fireContextMenuListenerPopup(popup, group);

//        JMenuItem delete = new JMenuItem(Res.getString("menuitem.delete"));
//        JMenuItem rename = new JMenuItem(Res.getString("menuitem.rename"));
        JMenuItem expand = new JMenuItem(Res.getString("menuitem.expand.all.groups"));
        JMenuItem collapse = new JMenuItem(Res.getString("menuitem.collapse.all.groups"));
        
//        if (!group.isSharedGroup()) {
//            popup.addSeparator();
//            popup.add(delete);
//            popup.add(rename);
//            
//        }
        popup.addSeparator();
        popup.add(expand);
        popup.add(collapse);

//        delete.addActionListener(new ActionListener() {
//            public void actionPerformed(ActionEvent e) {
//                int ok = JOptionPane.showConfirmDialog(group, Res.getString("message.delete.confirmation", group.getGroupName()), Res.getString("title.confirmation"), JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);
//                if (ok == JOptionPane.YES_OPTION) {
//                    String groupName = group.getGroupName();
//                    Roster roster = SparkManager.getConnection().getRoster();
//
//                    RosterGroup rosterGroup = roster.getGroup(groupName);
//                    if (rosterGroup != null) {
//                        for (RosterEntry entry : rosterGroup.getEntries()) {
//                            try {
//                                rosterGroup.removeEntry(entry);
//                            }
//                            catch (XMPPException e1) {
//                                Log.error("Error removing entry", e1);
//                            }
//                        }
//                    }
//
//                    // Remove from UI
//                    removeContactGroup(group);
//                    invalidate();
//                    repaint();
//                }
//
//            }
//        });


//        rename.addActionListener(new ActionListener() {
//            public void actionPerformed(ActionEvent e) {
//                String newName = JOptionPane.showInputDialog(group, Res.getString("label.rename.to") + ":", Res.getString("title.rename.roster.group"), JOptionPane.QUESTION_MESSAGE);
//                if (!ModelUtil.hasLength(newName)) {
//                    return;
//                }
//                String groupName = group.getGroupName();
//                Roster roster = SparkManager.getConnection().getRoster();
//
//                RosterGroup rosterGroup = roster.getGroup(groupName);
//                if (rosterGroup != null) {
//                    removeContactGroup(group);
//                    rosterGroup.setName(newName);
//                }
//
//            }
//        });
        
        expand.addActionListener(new ActionListener() {
           public void actionPerformed(ActionEvent e) {
         	Collection<SpecialistGroup> groups = getContactGroups();  
         	for (SpecialistGroup group : groups) {
               group.setCollapsed(false);
           }  
           }
        });
        
        collapse.addActionListener(new ActionListener() {
           public void actionPerformed(ActionEvent e) {
         	Collection<SpecialistGroup> groups = getContactGroups();  
         	for (SpecialistGroup group : groups) {
               group.setCollapsed(true);
           }  
           }
        });

        // popup.add(inviteFirstAcceptor);

        popup.show(group, e.getX(), e.getY());
        activeGroup = group;
    }

    /**
     * Shows popup for right-clicking of SpecialistItem.
     *
     * @param e    the MouseEvent
     * @param item the SpecialistItem
     */
    public void showPopup(MouseEvent e, final SpecialistItem item) {
        if (item.getJID() == null) {
            return;
        }

        activeItem = item;

        final JPopupMenu popup = new JPopupMenu();

        // Add Start Chat Menu
        //popup.add(chatMenu);

        // Add Send File Action
//        Action sendAction = new AbstractAction() {
//            public void actionPerformed(ActionEvent actionEvent) {
//                SparkManager.getTransferManager().sendFileTo(item);
//            }
//        };

//        sendAction.putValue(Action.SMALL_ICON, SparkRes.getImageIcon(SparkRes.DOCUMENT_16x16));
//        sendAction.putValue(Action.NAME, Res.getString("menuitem.send.a.file"));

//        if (item.getPresence() != null) {
//            popup.add(sendAction);
//        }

 //       popup.addSeparator();


//        String groupName = item.getGroupName();
//        SpecialistGroup contactGroup = getContactGroup(groupName);

//        // Only show "Remove Contact From Group" if the user belongs to more than one group.
//        // 从显示的组中删除联系人，前提是该联系人在别的组中也存在
//        if (!contactGroup.isSharedGroup() && !contactGroup.isOfflineGroup() && contactGroup != unfiledGroup) {
//            Roster roster = SparkManager.getConnection().getRoster();
//            RosterEntry entry = roster.getEntry(item.getJID());
//            if (entry != null) {
//                int groupCount = entry.getGroups().size();
//
//                //TODO: It should be possible to remove a user from the only group they're in
//                // which would put them into the unfiled group.
//                if (groupCount > 1) {
//                    popup.add(removeContactFromGroupMenu);
//                }
//
//            }
//        }

//        // Define remove entry action
//        Action removeAction = new AbstractAction() {
//            public void actionPerformed(ActionEvent e) {
//                removeContactFromRoster(item);
//            }
//        };

//        removeAction.putValue(Action.NAME, Res.getString("menuitem.remove.from.roster"));
//        removeAction.putValue(Action.SMALL_ICON, SparkRes.getImageIcon(SparkRes.SMALL_CIRCLE_DELETE));

//        // Check if user is in shared group.
//        boolean isInSharedGroup = false;
//        for (SpecialistGroup cGroup : new ArrayList<SpecialistGroup>(getContactGroups())) {
//            if (cGroup.isSharedGroup()) {
//                SpecialistItem it = cGroup.getContactItemByJID(item.getJID());
//                if (it != null) {
//                    isInSharedGroup = true;
//                }
//            }
//        }


//        if (!contactGroup.isSharedGroup() && !isInSharedGroup) {
//        	//从roster好友名单中，删除该联系人。
//            popup.add(removeAction);
//        }

//        popup.add(renameMenu);


//        Action viewProfile = new AbstractAction() {
//            public void actionPerformed(ActionEvent e) {
//                VCardManager vcardSupport = SparkManager.getVCardManager();
//                String jid = item.getJID();
//                vcardSupport.viewProfile(jid, SparkManager.getWorkspace());
//            }
//        };
//        viewProfile.putValue(Action.SMALL_ICON, SparkRes.getImageIcon(SparkRes.PROFILE_IMAGE_16x16));
//        viewProfile.putValue(Action.NAME, Res.getString("menuitem.view.profile"));
//
//        popup.add(viewProfile);
//
//
//        popup.addSeparator();
//
//        Action lastActivityAction = new AbstractAction() {
//            public void actionPerformed(ActionEvent actionEvent) {
//                try {
//                    LastActivity activity = LastActivityManager.getLastActivity(SparkManager.getConnection(), item.getJID());
//                    long idleTime = (activity.getIdleTime() * 1000);
//                    String time = ModelUtil.getTimeFromLong(idleTime);
//                    JOptionPane.showMessageDialog(getGUI(), Res.getString("message.idle.for", time), Res.getString("title.last.activity"), JOptionPane.INFORMATION_MESSAGE);
//                }
//                catch (Exception e1) {
//                    JOptionPane.showMessageDialog(getGUI(), Res.getString("message.unable.to.retrieve.last.activity", item.getJID()), Res.getString("title.error"), JOptionPane.ERROR_MESSAGE);
//                }
//
//            }
//        };
//
//        lastActivityAction.putValue(Action.NAME, Res.getString("menuitem.view.last.activity"));
//        lastActivityAction.putValue(Action.SMALL_ICON, SparkRes.getImageIcon(SparkRes.SMALL_USER1_STOPWATCH));
//
//        if (contactGroup == offlineGroup) {
//            popup.add(lastActivityAction);
//        }

//        Action subscribeAction = new AbstractAction() {
//            public void actionPerformed(ActionEvent e) {
//                String jid = item.getJID();
//                Presence response = new Presence(Presence.Type.subscribe);
//                response.setTo(jid);
//
//                SparkManager.getConnection().sendPacket(response);
//            }
//        };
//
//        subscribeAction.putValue(Action.SMALL_ICON, SparkRes.getImageIcon(SparkRes.SMALL_USER1_INFORMATION));
//        subscribeAction.putValue(Action.NAME, Res.getString("menuitem.subscribe.to"));

 //       SpecialistRoster roster =  ((ConsultantPlugin)PluginManager.getInstance().getPlugin(ConsultantPlugin.class)).getConsultantManager().getRoster();;
//        SpecialistRosterEntry entry = roster.getEntry(item.getJID());
//        if (entry != null && entry.getType() == SpecialistRosterPacket.ItemType.from) {
//            popup.add(subscribeAction);
//        }

        // Fire Context Menu Listener
        fireContextMenuListenerPopup(popup, item);

        SpecialistGroup group = getContactGroup(item.getGroupName());
        popup.show(group.getList(), e.getX(), e.getY());
    }

    public void showPopup(MouseEvent e, final Collection<SpecialistItem> items) {
        SpecialistGroup group = null;
        for (SpecialistItem item : items) {
            group = getContactGroup(item.getGroupName());
            break;
        }


        final JPopupMenu popup = new JPopupMenu();
//        final JMenuItem sendMessagesMenu = new JMenuItem(Res.getString("menuitem.send.a.message"), SparkRes.getImageIcon(SparkRes.SMALL_MESSAGE_IMAGE));
//
//
        fireContextMenuListenerPopup(popup, items);
//
//        popup.add(sendMessagesMenu);
//
//        sendMessagesMenu.addActionListener(new ActionListener() {
//            public void actionPerformed(ActionEvent e) {
//                sendMessages(items);
//            }
//        });

        try {
            popup.show(group.getList(), e.getX(), e.getY());
        }
        catch (NullPointerException ee) {
            // TODO: Should we do something here?
        }
    }

    private void clearSelectionList(SpecialistItem selectedItem) {
        // Check for null. In certain cases the event triggering the model might
        // not find the selected object.
        if (selectedItem == null) {
            return;
        }

        final SpecialistGroup owner = getContactGroup(selectedItem.getGroupName());
        for (SpecialistGroup contactGroup : new ArrayList<SpecialistGroup>(groupList)) {
            if (owner != contactGroup) {
                contactGroup.clearSelection();
            }
        }
    }


//    private void sendMessages(Collection<SpecialistItem> items) {
//        StringBuffer buf = new StringBuffer();
//        InputDialog dialog = new InputDialog();
//        final String messageText = dialog.getInput(Res.getString("title.broadcast.message"), Res.getString("message.enter.broadcast.message"), SparkRes.getImageIcon(SparkRes.BLANK_IMAGE), SparkManager.getMainWindow());
//        if (ModelUtil.hasLength(messageText)) {
//
//            final Map<String, Message> broadcastMessages = new HashMap<String, Message>();
//            for (SpecialistItem item : items) {
//                final Message message = new Message();
//                message.setTo(item.getJID());
//                message.setProperty("broadcast", true);
//                message.setBody(messageText);
//                if (!broadcastMessages.containsKey(item.getJID())) {
//                    buf.append(item.getDisplayName()).append("\n");
//                    broadcastMessages.put(item.getJID(), message);
//                }
//            }
//
//            for (Message message : broadcastMessages.values()) {
//                SparkManager.getConnection().sendPacket(message);
//            }
//
//            JOptionPane.showMessageDialog(SparkManager.getMainWindow(), Res.getString("message.broadcasted.to", buf.toString()), Res.getString("title.notification"), JOptionPane.INFORMATION_MESSAGE);
//        }
//
//
//    }

    // For plugin use only

    public void initialize() {
//    	setBorder(BorderFactory.createLineBorder(Color.LIGHT_GRAY));
        setBorder(BorderFactory.createEmptyBorder());

        // Add Contact List
        addContactListToWorkspace();

        // Hide top toolbar
        //SparkManager.getMainWindow().getTopToolBar().setVisible(false);

        final Runnable sharedGroupLoader = new Runnable() {
            public void run() {
                // Retrieve shared group list.
//                try {
//                    sharedGroups = SharedGroupManager.getSharedGroups(SparkManager.getConnection());
//                }
//                catch (XMPPException e) {
//                    Log.error("Unable to contact shared group info.", e);
//                }

                SwingUtilities.invokeLater(new Runnable() {
                    public void run() {
                        loadContactList();
                    }
                });

            }
        };

        TaskEngine.getInstance().submit(sharedGroupLoader);
    }

    private void loadContactList() {
        // Build the initial contact list.
        buildContactList();

        boolean show = localPreferences.isEmptyGroupsShown();

        // Hide all groups initially
        showEmptyGroups(show);
        
        // Hide all Offline Users
        showOfflineUsers(localPreferences.isOfflineUsersShown());

        // Add a subscription listener.
        addSubscriptionListener();

        addSpecialistContextListener();
        
        //监听专家队列人数的改变
        addQueueSizeListener();
//        // Load all plugins
//        SparkManager.getWorkspace().loadPlugins();
    }

    //fangt 换成自己实现的present，订阅present包只在专家登录和专家退出时有一个
    public void addSubscriptionListener() {
        // Add subscription listener
        PacketFilter packetFilter = new PacketTypeFilter(SpecialistPresence.class);
        PacketListener subscribeListener = new PacketListener() {
            public void processPacket(Packet packet) {
                final SpecialistPresence presence = (SpecialistPresence)packet;
//                if (presence.getType() == Presence.Type.subscribe) {
//                    SwingUtilities.invokeLater(new Runnable() {
//                        public void run() {
//                            subscriptionRequest(presence.getFrom());
//                        }
//                    });
//                }else
//                if (presence.getType() == Presence.Type.unsubscribe) {
//                    SwingUtilities.invokeLater(new Runnable() {
//                        public void run() {
//                        	SpecialistRoster roster =  ((ConsultantPlugin)PluginManager.getInstance().getPlugin(ConsultantPlugin.class)).getConsultantManager().getRoster();;
//                        	SpecialistRosterEntry entry = roster.getEntry(presence.getFrom());
//                            if (entry != null) {
//                                try {
////                                    removeContactItem(presence.getFrom());
////                                    roster.removeEntry(entry);
//                                }
//                                catch (XMPPException e) {
//                                    Presence unsub = new Presence(Presence.Type.unsubscribed);
//                                    unsub.setTo(presence.getFrom());
//                                    SparkManager.getConnection().sendPacket(unsub);
//                                    Log.error(e);
//                                }
//                            }
//                        }
//                    });
//
//
//                }
//                else if (presence.getType() == Presence.Type.subscribe) {
//                    // Find Contact in Contact List
//                    String jid = StringUtils.parseBareAddress(presence.getFrom());
//                    SpecialistItem item = getContactItemByJID(jid);
//
//                    // If item is not in the Contact List, add them.
//                    if (item == null) {
//                        final SpecialistRoster roster = ((ConsultantPlugin)PluginManager.getInstance().getPlugin(ConsultantPlugin.class)).getConsultantManager().getRoster();;
//                        SpecialistRosterEntry entry = roster.getEntry(jid);
//                        if (entry != null) {
//                            item = new SpecialistItem(entry.getName(), null, jid);
//                            moveToOffline(item);
//                            offlineGroup.fireContactGroupUpdated();
//                        }
//                    }
//                }
//                else if (presence.getType() == Presence.Type.unsubscribed) {
//                    SwingUtilities.invokeLater(new Runnable() {
//                        public void run() {
//                        	SpecialistRoster roster =  ((ConsultantPlugin)PluginManager.getInstance().getPlugin(ConsultantPlugin.class)).getConsultantManager().getRoster();;
//                        	SpecialistRosterEntry entry = roster.getEntry(presence.getFrom());
//                            if (entry != null) {
//                                try {
//                                    removeContactItem(presence.getFrom());
//                                    roster.removeEntry(entry);
//                                }
//                                catch (XMPPException e) {
//                                    Log.error(e);
//                                }
//                            }
//                            String jid = StringUtils.parseBareAddress(presence.getFrom());
//                            removeContactItem(jid);
//                        }
//                    });
//                }
//                else {
//
                    try {
                        initialPresences.add(presence);
                    }
                    catch (Exception e) {
                        Log.error(e);
                    }

                    int numberOfMillisecondsInTheFuture = 1000;

                    presenceTimer.schedule(new TimerTask() {
                        public void run() {
                            SwingUtilities.invokeLater(new Runnable() {
                                public void run() {
                                    for (SpecialistPresence userToUpdate : new ArrayList<SpecialistPresence>(initialPresences)) {
                                        initialPresences.remove(userToUpdate);
                                        try {
                                            updateUserPresence(userToUpdate);
                                        }
                                        catch (Exception e) {
                                            Log.error(e);
                                        }

                                    }
                                }
                            });
                        }
                    }, numberOfMillisecondsInTheFuture);
                }
//            }
        };

        SparkManager.getConnection().addPacketListener(subscribeListener, packetFilter);
    }


    public void shutdown() {
        //saveState();
    }

    public boolean canShutDown() {
        return true;
    }
   
    /**
     * 
     * 添加联系人面板到主界面中
     * 
     */
    private void addContactListToWorkspace() {
        Workspace workspace = SparkManager.getWorkspace();
        SparkTab consultantTab = workspace.getWorkspacePane().addTab("座席", SparkRes.getImageIcon(SparkRes.SMALL_ALL_CHATS_IMAGE), this); //NOTRANS
        int tabPosition = workspace.getWorkspacePane().getTabPosition(consultantTab);
        workspace.getWorkspacePane().setSelectedIndex(tabPosition);
        // Add To Contacts Menu
       // final JMenu contactsMenu = SparkManager.getMainWindow().getMenuByName(Res.getString("menuitem.contacts"));
        //JMenuItem addContactsMenu = new JMenuItem("", SparkRes.getImageIcon(SparkRes.USER1_ADD_16x16));
        //ResourceUtils.resButton(addContactsMenu, Res.getString("menuitem.add.contact"));
        //ResourceUtils.resButton(addContactGroupMenu, Res.getString("menuitem.add.contact.group"));

        //contactsMenu.add(addContactsMenu);
        //contactsMenu.add(addContactGroupMenu);
//        addContactsMenu.addActionListener(new ActionListener() {
//            public void actionPerformed(ActionEvent e) {
//            	new UserSearchService().search(null);
//            	//new RosterDialog().showRosterDialog();
//            }
//        });

//        addContactGroupMenu.addActionListener(new ActionListener() {
//            public void actionPerformed(ActionEvent e) {
//            	String groupName = JOptionPane.showInputDialog(getGUI(), Res.getString("message.name.of.group") + ":", Res.getString("title.add.new.group"), JOptionPane.QUESTION_MESSAGE);
//                if (ModelUtil.hasLength(groupName)) {
//                	groupName = groupName.trim();
//                    SpecialistGroup contactGroup = getContactGroup(groupName);
//                    if (contactGroup == null) {
//                        contactGroup = addContactGroup(groupName);
//                        contactGroup.setVisible(true);
//                        validateTree();
//                        repaint();
//                    }else{
//                    	JOptionPane.showMessageDialog(SparkManager.getMainWindow(), Res.getString("menuitem.add.contact.existed.error"), Res.getString("title.error"), JOptionPane.ERROR_MESSAGE);
//                    }
//                }
//            }
//        });

        // Add Toggle Contacts Menu
//        ResourceUtils.resButton(showHideMenu, Res.getString("menuitem.show.empty.groups"));
//        contactsMenu.add(showHideMenu);
//
//        showHideMenu.addActionListener(new ActionListener() {
//            public void actionPerformed(ActionEvent e) {
//                showEmptyGroups(showHideMenu.isSelected());
//            }
//        });

//        ResourceUtils.resButton(showOfflineGroupMenu, Res.getString("menuitem.show.offline.group"));
//        contactsMenu.add(showOfflineGroupMenu);
//        
//        showOfflineGroupMenu.addActionListener(new ActionListener() {
//            public void actionPerformed(ActionEvent actionEvent) {
//                showOfflineGroup(showOfflineGroupMenu.isSelected());
//            }
//        });
        
//        ResourceUtils.resButton(showOfflineUsersMenu, Res.getString("menuitem.show.offline.users"));
////        contactsMenu.add(showOfflineUsersMenu);
//        
//        showOfflineUsersMenu.addActionListener(new ActionListener() {
//            public void actionPerformed(ActionEvent actionEvent) {
//                showOfflineUsers(showOfflineUsersMenu.isSelected());
//            }
//        });
//        
//        // Show or Hide Offline Group
//        showOfflineGroupMenu.setSelected(localPreferences.isOfflineGroupVisible());
//        showOfflineGroup(localPreferences.isOfflineGroupVisible());
//
//        // sets showOfflineUsersMenu selected or not selected
//        showOfflineUsersMenu.setSelected(localPreferences.isOfflineUsersShown());
        
        // Initialize vcard support
        //SparkManager.getVCardManager();
    }

    /**
     * Toggles the visibility of empty groups.
     *
     * @param show true to display empty contact groups within the ContactList, otherwise false.
     */
    private void showEmptyGroups(boolean show) {
        for (SpecialistGroup group : getContactGroups()) {
            if (group != offlineGroup) {
                if (show) {
                    group.setVisible(true);
                } else {
                    // Never hide offline group.
                    group.setVisible(group.hasAvailableContacts());
                }
            }
        }

        localPreferences.setEmptyGroupsShown(show);
//        showHideMenu.setSelected(show);
        SettingsManager.saveSettings();
    }
    
    private void showOfflineUsers(boolean show) {
       for (SpecialistGroup group : getContactGroups()) 
       {
      	  if(group != offlineGroup)
      	  {
      		  group.toggleOfflineVisibility(show);
      	  }
      	  
      	  if (group == offlineGroup) {
               if (show) 
               {
                   group.setVisible(true);
//                   showOfflineGroupMenu.setEnabled(true);
//                   showOfflineGroupMenu.setSelected(localPreferences.isOfflineGroupVisible());
//                   showOfflineGroup(showOfflineGroupMenu.isSelected());
               } 
               else 
               {
                   group.setVisible(false);
//                   showOfflineGroupMenu.setEnabled(false);
               }
           }
       }
       localPreferences.setOfflineUsersShown(show);
       SettingsManager.saveSettings();
   }

    /**
     * Toggles the visiblity of the Offline Group.
     *
     * @param show true to display the offline group, otherwise false.
     */
    private void showOfflineGroup(boolean show) {
        // Save in preferences
        localPreferences.setOfflineGroupVisible(show);
        SettingsManager.saveSettings();

        // Toggle Visibility of Offline Group.
        offlineGroup.setVisible(show);

        if (show) {
            // Remove offline items from all groups.
            for (SpecialistGroup group : getContactGroups()) {
                group.toggleOfflineVisibility(false);
            }
        }
        else {
            // Remove offline items from all groups.
            for (SpecialistGroup group : getContactGroups()) {
                group.toggleOfflineVisibility(true);
            }
        }
    }


    /**
     * Sorts ContactGroups
     */
    public static final Comparator<SpecialistGroup> GROUP_COMPARATOR = new Comparator<SpecialistGroup>() {
        public int compare(SpecialistGroup group1, SpecialistGroup group2) {
            // Make sure that offline group is always on bottom.
            if (group2.isOfflineGroup()) {
                return -1;
            }

            return group1.getGroupName().trim().toLowerCase().compareTo(group2.getGroupName().trim().toLowerCase());
        }
    };

    public JPanel getMainPanel() {
        return domainPanel;
    }

    public List<SpecialistGroup> getContactGroups() {
        final List<SpecialistGroup> gList = new ArrayList<SpecialistGroup>(groupList);
        Collections.sort(gList, GROUP_COMPARATOR);
        return gList;
    }

//    private void subscriptionRequest(final String jid) {
//        final SubscriptionDialog subscriptionDialog = new SubscriptionDialog();
//        subscriptionDialog.invoke(jid);
//    }

    public void addContextMenuListener(ContextMenuListener listener) {
        contextListeners.add(listener);
    }

    public void removeContextMenuListener(ContextMenuListener listener) {
        contextListeners.remove(listener);
    }

    public void fireContextMenuListenerPopup(JPopupMenu popup, Object object) {
        for (ContextMenuListener listener : new ArrayList<ContextMenuListener>(contextListeners)) {
            listener.poppingUp(object, popup);
        }
    }

    public JComponent getGUI() {
        return this;
    }

    public SpecialistGroup getActiveGroup() {
        return activeGroup;
    }

    public Collection<SpecialistItem> getSelectedUsers() {
        final List<SpecialistItem> list = new ArrayList<SpecialistItem>();

        for (SpecialistGroup group : getContactGroups()) {
            for (SpecialistItem item : group.getSelectedContacts()) {
                list.add(item);
            }
        }
        return list;
    }

    private void checkGroup(SpecialistGroup group) {
        if (!group.hasAvailableContacts() && group != offlineGroup && group != unfiledGroup){// && !showHideMenu.isSelected()) {
            group.setVisible(false);
        }
    }

//    public void addFileDropListener(FileDropListener listener) {
//        dndListeners.add(listener);
//    }
//
//    public void removeFileDropListener(FileDropListener listener) {
//        dndListeners.remove(listener);
//    }

//    public void fireFilesDropped(Collection files, SpecialistItem item) {
//        for (FileDropListener fileDropListener : new ArrayList<FileDropListener>(dndListeners)) {
//            fileDropListener.filesDropped(files, item);
//        }
//    }

    public void contactItemAdded(SpecialistItem item) {
        fireContactItemAdded(item);
    }

    public void contactItemRemoved(SpecialistItem item) {
        fireContactItemRemoved(item);
    }

    /*
        Adding ContactListListener support.
    */

    public void addContactListListener(SpecialistListListener listener) {
        contactListListeners.add(listener);
    }

    public void removeContactListListener(SpecialistListListener listener) {
        contactListListeners.remove(listener);
    }

    public void fireContactItemAdded(SpecialistItem item) {
        for (SpecialistListListener contactListListener : new ArrayList<SpecialistListListener>(contactListListeners)) {
            contactListListener.contactItemAdded(item);
        }
    }

    public void fireContactItemRemoved(SpecialistItem item) {
        for (SpecialistListListener contactListListener : new ArrayList<SpecialistListListener>(contactListListeners)) {
            contactListListener.contactItemRemoved(item);
        }
    }

    public void fireContactGroupAdded(SpecialistGroup group) {
        for (SpecialistListListener contactListListener : new ArrayList<SpecialistListListener>(contactListListeners)) {
            contactListListener.contactGroupAdded(group);
        }
    }

    public void fireContactGroupRemoved(SpecialistGroup group) {
       for (SpecialistListListener contactListListener : new ArrayList<SpecialistListListener>(contactListListeners)) {
            contactListListener.contactGroupRemoved(group);
        }
    }

    public void fireContactItemClicked(SpecialistItem contactItem) {
        for (SpecialistListListener contactListListener : new ArrayList<SpecialistListListener>(contactListListeners)) {
            contactListListener.contactItemClicked(contactItem);
        }
    }

    public void fireContactItemDoubleClicked(SpecialistItem contactItem) {
        for (SpecialistListListener contactListListener : new ArrayList<SpecialistListListener>(contactListListeners)) {
            contactListListener.contactItemDoubleClicked(contactItem);
        }
    }


    public void uninstall() {
        // Do nothing.
    }

//    private void saveState() {
//        if (props == null) {
//            return;
//        }
//        for (SpecialistGroup contactGroup : getContactGroups()) {
//            props.put(contactGroup.getGroupName(), Boolean.toString(contactGroup.isCollapsed()));
//        }
//
//        try {
//            props.store(new FileOutputStream(propertiesFile), "Tracks the state of groups.");
//        }
//        catch (IOException e) {
//            Log.error("Unable to save group properties.", e);
//        }
//
//    }
    
    private void addQueueSizeListener(){
    	PacketFilter packetFilter = new PacketTypeFilter(SpecialistQueueSize.class);
    	PacketListener queueSizeListener = new PacketListener() {
    		
			@Override
			public void processPacket(Packet packet) {
				final SpecialistQueueSize queueSizePacket = (SpecialistQueueSize)packet;
				//获取专家队列人数改变的信息--对应的specialistItem中的排队人数改变
				final Map<String, String> queueSizes = queueSizePacket.getQueueSizes();
				for (String spid : queueSizes.keySet()) {
					String queueSize = queueSizePacket.getSizeText(spid);
					changeSpecialistQueueSize(spid,queueSize);
				}
			}
		};
    	SparkManager.getConnection().addPacketListener(queueSizeListener, packetFilter);
    }
    
    private void changeSpecialistQueueSize(String spid,String queueSize){
    	final SpecialistRoster roster = ConsultantManager.getInstance(SparkManager.getConnection()).getRoster();

        SpecialistRosterEntry entry = roster.getEntry(spid);
        for (SpecialistRosterGroup rosterGroup : entry.getGroups()) {
        	SpecialistGroup contactGroup = getContactGroup(rosterGroup.getName());
            if (contactGroup == null) {
                return;
            }else{
            	SpecialistItem contactItem = null;
                if (contactGroup.getContactItemBySpid(entry.getName()) == null) {
                    return;
                }else{
                	contactItem = contactGroup.getContactItemBySpid(entry.getName());
                	contactItem.setQueueSizeText(queueSize);
                }
            }
        }
             
    }
    
    public void addSpecialistContextListener(){
        // Add ContactList items.
    	final SpecialistList list= this;
    	
        final Action joinAction = new AbstractAction() {
            public void actionPerformed(ActionEvent actionEvent) {

            	for(SpecialistItem si:list.getSelectedUsers()){
            		joinSpecialQueue(si.getAlias());
            	}
            }
        };

        joinAction.putValue(Action.NAME, "加入队列");
        joinAction.putValue(Action.SMALL_ICON, SparkRes.getImageIcon(SparkRes.SMS_SEND_TO_GROUP));


        final Action detailAction = new AbstractAction() {
            public void actionPerformed(ActionEvent actionEvent) {

            	if(list.getSelectedUsers().iterator().hasNext()){
            		String spid = list.getSelectedUsers().iterator().next().getAlias();
            		
                	SpecialistVCardVeiwer spViewer = new SpecialistVCardVeiwer(spid);
                    final JFrame dlg = new JFrame(Res.getString("title.view.profile.for", spid));
                    
                    // The user should only be able to close this dialog.
                    Object[] options = {"确定"};
                    final JOptionPane pane = new JOptionPane(spViewer,JOptionPane.PLAIN_MESSAGE , JOptionPane.OK_CANCEL_OPTION, null, options, options[0]);

                    //  mainPanel.add(pane, new GridBagConstraints(0, 1, 1, 1, 1.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 5, 5, 5), 0, 0));

                    PropertyChangeListener changeListener = new PropertyChangeListener() {
                        public void propertyChange(PropertyChangeEvent e) {
                            String value = (String)pane.getValue();
                            if (value.equals("确定")) {
                                pane.removePropertyChangeListener(this);
                                dlg.dispose();
                            }
                        }
                    };
                    pane.addPropertyChangeListener(changeListener);
                    
                    dlg.setIconImage(SparkRes.getImageIcon(SparkRes.PROFILE_IMAGE_16x16).getImage());

                    dlg.pack();
                    dlg.setSize(350, 250);
                    dlg.setResizable(true);
                    dlg.setContentPane(pane);
                    dlg.setLocationRelativeTo(SparkManager.getMainWindow());

                    dlg.setVisible(true);
                    dlg.toFront();
                    dlg.requestFocus();
            	}

            }
        };

        detailAction.putValue(Action.NAME, "专家资料");
        detailAction.putValue(Action.SMALL_ICON, SparkRes.getImageIcon(SparkRes.EXPERT_INFORMATION));


        this.addContextMenuListener(new ContextMenuListener() {
            public void poppingUp(Object component, JPopupMenu popup) {
                if (component instanceof SpecialistItem &&  list.getSelectedUsers().size() > 0 && ((SpecialistItem)component).getPresence().isAvailable()) {
                    popup.add(joinAction);
                }
                if(component instanceof SpecialistItem &&  list.getSelectedUsers().size() == 1){
                    popup.add(detailAction);
                }
            }

            public void poppingDown(JPopupMenu popup) {

            }

            public boolean handleDefaultAction(MouseEvent e) {
                return false;
            }
        });
    }
    
    private void joinSpecialQueue(String spid){
    	SpecialistNotifyPacket result = ConsultantManager.getInstance(SparkManager.getConnection()).joinSpecialistQueue(spid);
		if(result.getStatus().equals("yes")){
			SpecialistQueueManager.getInstance().putWhenJoin(spid);
			JOptionPane.showMessageDialog(SparkManager.getMainWindow(), "加入成功");
		}
		else{
			if(result.getResult().equals("busy"))
				JOptionPane.showMessageDialog(SparkManager.getMainWindow(), "专家正忙，队列已满");
			else if(result.getResult().equals("repeat"))
				JOptionPane.showMessageDialog(SparkManager.getMainWindow(), "重复加入队列");
			else if(result.getResult().equals("sameone"))
				JOptionPane.showMessageDialog(SparkManager.getMainWindow(), "不能加入自己队列");
			else
				JOptionPane.showMessageDialog(SparkManager.getMainWindow(), "无法加入队列");
		}
    }


    public void connectionClosed() {
        // No reason to reconnect.
        retryPanel.setClosedOnError(false);

        // Show MainWindow
        SparkManager.getMainWindow().setVisible(true);

        // Flash That Window.
        SparkManager.getNativeManager().flashWindowStopOnFocus(SparkManager.getMainWindow());

        workspace.changeCardLayout(RETRY_PANEL);

        String errorMessage = Res.getString("message.disconnected.error");

        retryPanel.setDisconnectReason(errorMessage);

        removeAllUsers();

    }

    private void reconnect(final String message) {
        // Show MainWindow
        SparkManager.getMainWindow().setVisible(true);

        // Flash That Window.
        SparkManager.getNativeManager().flashWindowStopOnFocus(SparkManager.getMainWindow());

        workspace.changeCardLayout(RETRY_PANEL);

        retryPanel.setDisconnectReason(message);

        removeAllUsers();
    }

    public void clientReconnected() {
        workspace.changeCardLayout(Workspace.WORKSPACE_PANE);

        buildContactList();

//        final TimerTask updatePresence = new TimerTask() {
//            public void run() {
//                final Presence myPresence = SparkManager.getWorkspace().getStatusBar().getPresence();
//            	final SpecialistPresence myPresence = Con
//                SparkManager.getSessionManager().changePresence(myPresence);
//
//                XMPPConnection con = SparkManager.getConnection();
//                final SpecialistRoster roster =  ((ConsultantPlugin)PluginManager.getInstance().getPlugin(ConsultantPlugin.class)).getConsultantManager().getRoster();;
//
//                for (SpecialistRosterEntry entry : roster.getEntries()) {
//                    String user = entry.getUser();
////                    Presence presence = roster.getPresence(user);
//                    
//                    try {
//                        updateUserPresence(presence);
//                    }
//                    catch (Exception e) {
//                        Log.error(e);
//                    }
//                }
//            }
//        };

//        TaskEngine.getInstance().schedule(updatePresence, 5000);


    }

    public void connectionClosedOnError(final Exception ex) {
        String errorMessage = Res.getString("message.disconnected.error");

        if (ex != null && ex instanceof XMPPException) {
            XMPPException xmppEx = (XMPPException)ex;
            StreamError error = xmppEx.getStreamError();
            String reason = error.getCode();

            if ("conflict".equals(reason)) {
                errorMessage = Res.getString("message.disconnected.conflict.error");
            }
            else if ("system-shutdown".equals(reason)) {
                errorMessage = Res.getString("message.disconnected.shutdown");
            }
            else {
                errorMessage = Res.getString("message.general.error", reason);
            }
        }

        final String message = errorMessage;
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                retryPanel.setClosedOnError(true);
                reconnect(message);
            }
        });
    }

    private void removeAllUsers() {
        // Behind the scenes, move everyone to the offline group.
        for (SpecialistGroup contactGroup : new ArrayList<SpecialistGroup>(getContactGroups())) {
            contactGroup.removeAllContacts();
        }

    }

    public void reconnectingIn(int i) {
        if (i == 0) {
            retryPanel.setReconnectText(Res.getString("message.reconnect.attempting"));
        }
        else {
            retryPanel.setReconnectText(Res.getString("message.reconnect.wait",i));
        }
    }

    public void reconnectionSuccessful() {
        clientReconnected();
    }

    public void reconnectionFailed(Exception exception) {
        retryPanel.setReconnectText(Res.getString("message.reconnect.failed"));
    }

	/**
	 * 将组（除默认的"我的联系人"组外）中不在线的联系人移到不在线列表中
	 * 即移到每个组的离线联系人部分
	 *  
	 * @param contactItem
	 */
	public void moveToOffline(SpecialistItem contactItem) {
		moveToOffline(contactItem, false);
	}
	
	/**
	 * 
	 * 	将"我的联系人"组中的联系人，移到不在线列表中
	 *  对于好友列表roster中未有分组的，都按unfiled为true来处理
	 *  
	 * @param contactItem
	 */
	public void moveUnfiledToOffline(SpecialistItem contactItem){
		moveToOffline(contactItem, true);
	}
    
    /**

     *  Moves a <code>SpecialistItem</code> to an offline state.
     * @param contactItem the SpecialistItem.
     */
    private void moveToOffline(SpecialistItem contactItem,boolean isUnfiledForce) {
        offlineGroup.addContactItem(contactItem);
        	  
//        String jid = contactItem.getJID();
        String spid = contactItem.getAlias();
//        Boolean isFiledTemp = false;

        final SpecialistRoster roster =  ((ConsultantPlugin)PluginManager.getInstance().getPlugin(ConsultantPlugin.class)).getConsultantManager().getRoster();

        for (SpecialistRosterGroup group : roster.getEntry(spid).getGroups()) {
            SpecialistGroup contactGroup = getContactGroup(group.getName());
            if (contactGroup != null) {
//            	isFiledTemp = true;
                contactGroup.addOfflineContactItem(contactItem.getAlias(), contactItem.getNickname(), contactItem.getJID(), contactItem.getStatus());
            }
        }
        //如果强制设定联系人没有分组，则将该联系人加入到默认的组(即unFiledGroup)中
        //如果没有强制,则根据该联系人具体情况:是否有分组，来进行具体的设置
//        if (isUnfiledForce) {
//            unfiledGroup.addOfflineContactItem(contactItem.getAlias(), contactItem.getNickname(), contactItem.getJID(), contactItem.getStatus());
//        }else if(!isFiledTemp){
//        	unfiledGroup.addOfflineContactItem(contactItem.getAlias(), contactItem.getNickname(), contactItem.getJID(), contactItem.getStatus());
//        }
        
        if(localPreferences.isOfflineUsersShown() == false)
        {
	        for (SpecialistGroup group : getContactGroups()) 
	        {
	       	  if(group != offlineGroup)
	       	  {
	       		  group.toggleOfflineVisibility(false);
	       	  }
	        }
        }
    }
    
    /**
     * 得到用户名单,主要用于联系人的快速搜索
     * 
     * @return
     */
    public Map<String,ContactBean> getAllContacts() {
		return allContacts;
	}

    /**
     * Sorts ContactItems.
     */
    public final static Comparator<SpecialistItem> ContactItemComparator = new Comparator<SpecialistItem>() {
        public int compare(SpecialistItem item1, SpecialistItem item2) {
            return item1.getDisplayName().toLowerCase().compareTo(item2.getDisplayName().toLowerCase());
        }
    };

}







